//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
//
// Copyright (c) 2002 BSQUARE Corporation.  All rights reserved.
// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE
//
// Module Name:
//
//    Main.c
//
// Abstract:
//
//    Driver entry points for PXA SDIO driver
//
// Notes:
//
///////////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <monahans.h>
#include <Devload.h>
//#include "SDCardDDK.h"
//#include "SDHCD.h"
#include "SD.h"
//#include "args.h"
//#include "ioctl_cfg.h"

    // initialize debug zones
SD_DEBUG_INSTANTIATE_ZONES(
     TEXT("PXA SDIO Driver"), // module name
     ZONE_ENABLE_INIT | ZONE_ENABLE_ERROR | ZONE_ENABLE_WARN /*| SDH_SDBUS_INTERACTION_ZONE_ON*/,
     // | SDH_RECEIVE_ZONE_ON | SDH_TRANSMIT_ZONE_ON | SDH_SEND_ZONE_ON,
     //| SDH_INTERRUPT_ZONE_ON,    // initial settings
     TEXT("Interrupts"),
     TEXT("Send Handler "),
     TEXT("Responses"),
     TEXT("Receive Data"),
     TEXT("Clock Control"),
     TEXT("Transmit Data"),
     TEXT("Function"),
     TEXT("SDBus Interaction"),
     TEXT(""),
     TEXT(""),
     TEXT(""));

#define SDH_SLOTS 1
#define SDH_REGISTRY_BASE_PATH TEXT("Drivers\\SDCARD\\HostController\\XSDSC")



///////////////////////////////////////////////////////////////////////////////
//  DllMain - the main dll entry point
//  Input:  hInstance - the instance that is attaching
//          Reason - the reason for attaching
//          pReserved -
//  Output:
//  Return: TRUE
//  Notes:  this is only used to initialize the zones
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI DllMain(HINSTANCE  hInstance,
                       ULONG      Reason,
                       LPVOID     pReserved)
{
    if ( Reason == DLL_PROCESS_ATTACH ) {
        SD_DEBUG_ZONE_REGISTER(hInstance, SDH_REGISTRY_BASE_PATH);
        DisableThreadLibraryCalls( (HMODULE) hInstance );

        if( !SDInitializeCardLib() )
        {
            return FALSE;
        }
        else if( !SD_API_SUCCESS( SDHCDInitializeHCLib() ) )
        {
            SDDeinitializeCardLib();
            return FALSE;
        }
    }

    if ( Reason == DLL_PROCESS_DETACH ) {
        SDHCDDeinitializeHCLib();
        SDDeinitializeCardLib();
    }

    return(TRUE);
}

#define SDCLOCKOFFTIMEOUT 2000

DWORD WINAPI
SDClockOnOffProc(PVOID pvParam)
{
    PSDH_HARDWARE_CONTEXT pController = (PSDH_HARDWARE_CONTEXT)pvParam;
    //TCHAR szBuf[128], szErrorString[256];
    HANDLE hev[3];
    BOOL fDone = FALSE;
    DWORD dwTimeout;
    BOOL ClockOn = FALSE;

    // wait until we're told to exit or until something happens
    hev[0] = pController->hClockOn;

    dwTimeout = 1;

    while(1) {
        DWORD dwStatus = WaitForSingleObject(hev[0], dwTimeout);

        switch(dwStatus) {
        case WAIT_TIMEOUT:  //timeput: release MiniOP and set status ready, and turn off clock
            if(FALSE == pController->fCMD)
            {
                EnterCriticalSection(&pController->csMiniOPCriticalSection);
                if(TRUE == pController->fMiniOPSet){
                    // Timeout Has Occurred. Send Proc Notify to IPM.
                    DWORD dwProcState = IPM_PROCESSOR_D0_RDY | IPM_PROCESSOR_RING_OSC_RDY | IPM_PROCESSOR_D2_RDY| IPM_PROCESSOR_D1_RDY;
                    //NKDbgPrintfW(TEXT("[SDH] Hysteresis timeout event received\r\n"));
                    // Notify IPM & set MiniOP
                        RETAILMSG(1, (_T("[%s] Notify IPM Ready For Processor state. dwProcState=%x\r\n"),pController->szName,dwProcState));
                    if ( IPM_STATUS_SUCCESS!=IPM_NotifyReadyForProcState(pController->ClientID, dwProcState ,3000)){
                        RETAILMSG(1, (_T("[%s] Notify IPM Ready For Processor state FAILED\r\n")));
                    }
                    /*RETAILMSG(1, (_T("[%s] Releasing MinOP \r\n"),pController->szName));
                    IPM_ReleaseMinOp(pController->ClientID, 1000);*/
                    pController->fMiniOPSet = FALSE;
                }
                if( FALSE == pController->fClockAlwaysOn ){
                    SDClockOff(pController);
                    SDCKENOnOff(pController, FALSE);
                }
                LeaveCriticalSection(&pController->csMiniOPCriticalSection);
    
                dwTimeout = INFINITE;
            }
            else
            {
                pController->fCMD=FALSE;
            }
            break;

        case (WAIT_OBJECT_0 + 0):   // hClockOn: set timeout and status
            dwTimeout = SDCLOCKOFFTIMEOUT;
            ResetEvent(pController->hClockOn);
            break;

        default:
            break;
        }
    }

    return 0;
}


///////////////////////////////////////////////////////////////////////////////
//  SDH_Deinit - the deinit entry point
//  Input:  hDeviceContext - the context returned from SDH_Init
//  Output:
//  Return: always returns TRUE
//  Notes:
///////////////////////////////////////////////////////////////////////////////
BOOL SDH_Deinit(DWORD hDeviceContext)
{
    PSDCARD_HC_CONTEXT pHostContext;
    PSDH_HARDWARE_CONTEXT pController;
    DbgPrintZo(SDCARD_ZONE_INIT, (TEXT("SDH: +SDH_Deinit\n")));

    pHostContext = (PSDCARD_HC_CONTEXT)hDeviceContext;
    pController = GetExtensionFromHCDContext(PSDH_HARDWARE_CONTEXT, pHostContext);

    if (NULL == pHostContext)
        return TRUE;

        // deregister the host controller
    SDHCDDeregisterHostController(pHostContext);

    if( pHostContext && pHostContext->pHCSpecificContext )
    {
        free( pHostContext->pHCSpecificContext );
    }

        // cleanup the context
    SDHCDDeleteContext((PSDCARD_HC_CONTEXT)hDeviceContext);

    DeleteCriticalSection(&pController->csMiniOPCriticalSection);

    return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
//  SDH_Init - the init entry point
//  Input:  dwContext - the context for this init
//  Output:
//  Return: returns instance context
//  Notes:
///////////////////////////////////////////////////////////////////////////////
DWORD SDH_Init(DWORD dwContext)
{
    PSDCARD_HC_CONTEXT      pHostContext = NULL;   // new HC context
    SD_API_STATUS           status;         // SD status
    PSDH_HARDWARE_CONTEXT pController;    // new instance
    HKEY hKeyDevice;
    LPCTSTR pszActiveKey;
    DWORD dwStatus, dwSize, dwType;
//    BSP_ARGS args;
//    DWORD size;

    DbgPrintZo(SDCARD_ZONE_INIT, (TEXT("SDH: +SDH_Init\r\n")));

    DbgPrintZo(SDCARD_ZONE_INIT, (TEXT("SDH: Active RegPath: %s \r\n"),
        (PTSTR)dwContext));

    pController = NULL;

    // allocate the context
    status = SDHCDAllocateContext(SDH_SLOTS,
                                  &pHostContext);

    if (!SD_API_SUCCESS(status)) {
        DbgPrintZo(SDCARD_ZONE_ERROR,
            (TEXT("SDH: Failed to allocate context : 0x%08X \n"), status));
        return 0;
    }

    // create our extension
    pController = (PSDH_HARDWARE_CONTEXT)malloc( sizeof(SDH_HARDWARE_CONTEXT) );
    if( pController == NULL )
    {
        DbgPrintZo(SDCARD_ZONE_ERROR,
            (TEXT("SDH: Failed to allocate extension\n")));
        return 0;
    }
    memset( pController, 0, sizeof(SDH_HARDWARE_CONTEXT) );

    // Set our extension
    pHostContext->pHCSpecificContext = pController;

    pController = GetExtensionFromHCDContext(PSDH_HARDWARE_CONTEXT, pHostContext);

    // get device name from registry
    dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)dwContext, 0, 0, &hKeyDevice);
    if(dwStatus != ERROR_SUCCESS)
    {
        NKDbgPrintfW(TEXT("RegOpenKeyEx failed with %u\r\n"), dwStatus);
        return 0;
    }

    dwSize = sizeof(pController->szName);
    dwStatus = RegQueryValueEx(hKeyDevice, L"Name", NULL,
                               &dwType, (LPBYTE)pController->szName, &dwSize);
    if(dwStatus != ERROR_SUCCESS)
    {
        NKDbgPrintfW(TEXT("RegQueryValueEx failed with %u\r\n"), dwStatus);
        return 0;

    }

    pszActiveKey = (LPCTSTR) dwContext;
    hKeyDevice = OpenDeviceKey(pszActiveKey);
    if (!hKeyDevice || !LoadRegistrySettings(hKeyDevice, pController) ) {
        DbgPrintZo(SDCARD_ZONE_ERROR,
        (TEXT("SDH: Failed load the registry settings\r\n")));
        return 0;
    }
    RegCloseKey( hKeyDevice );


    // IPM Registration:

    pController->hClockOn = NULL;
    pController->fCMD = FALSE;

    NKDbgPrintfW (_T("[%s] Sending IPM Registration Request \r\n"),pController->szName);
    status = IPM_Register(pController->szName, &(pController->ClientID) ,3000);
    if ( status==IPM_STATUS_SUCCESS)
    {
        DWORD dwProcState;
        NKDbgPrintfW (_T("[%s] Registration Completed, client id is 0x%x\r\n"),pController->szName,pController->ClientID);

        dwProcState = IPM_PROCESSOR_D0_RDY | IPM_PROCESSOR_RING_OSC_RDY | IPM_PROCESSOR_D2_RDY| IPM_PROCESSOR_D1_RDY; // Initial

        // Notify IPM
        NKDbgPrintfW(_T("[%s] Initial Notify IPM Ready For Processor state. dwProcState=%x \r\n"),pController->szName,dwProcState);
        if ( IPM_NotifyReadyForProcState(pController->ClientID, dwProcState ,3000)==IPM_STATUS_SUCCESS)
        {
            NKDbgPrintfW(_T("[%s] Notify IPM Ready For Processor state for driver Success!\r\n"),pController->szName);
        }
        else
        {
            NKDbgPrintfW(_T("[%s] Notify IPM Ready For Processor state for driver FAILED\r\n"),pController->szName);
        }

        // Create events for ClockOn ClockOff events.
        pController->hClockOn  = CreateEvent( NULL , TRUE , FALSE , NULL );

        InitializeCriticalSection(&pController->csMiniOPCriticalSection);
        pController->hClockHysteresisThread  = CreateThread(NULL, 0, SDClockOnOffProc, pController, 0, NULL);


    }
    else
        NKDbgPrintfW (_T("[%s] Registration Failed, IPM Error %d\r\n"),pController->szName, status);


    DbgPrintZo(SDCARD_ZONE_INIT,
               (TEXT("SDH: Real RegPath: %s \r\n"),pController->RegPath));


    // save off the host context
    pController->pHCContext = pHostContext;

    // set the name
    SDHCDSetHCName(pHostContext, TEXT("Littleton"));

    // set init handler
    SDHCDSetControllerInitHandler(pHostContext,SDInitialize);
    // set deinit handler
    SDHCDSetControllerDeinitHandler(pHostContext, SDDeinitialize);
    // set the bus request handler
    SDHCDSetBusRequestHandler(pHostContext,SDHBusRequestHandler);
    // set the cancel I/O handler
    SDHCDSetCancelIOHandler(pHostContext, SDHCancelIoHandler);
    // set the slot option handler
    SDHCDSetSlotOptionHandler(pHostContext, SDHSlotOptionHandler);


    // now register the host controller
    status = SDHCDRegisterHostController(pHostContext);

    if (!SD_API_SUCCESS(status)) {
        if( pController )
        {
            free( pController );
        }
        SDHCDDeleteContext(pHostContext);
        DbgPrintZo(SDCARD_ZONE_ERROR,
                (TEXT("SDH: Failed to register host controller: %0x08X \n"),status));
        return 0;
    }

    DbgPrintZo(SDCARD_ZONE_INIT, (TEXT("SDH: -SDH_Init\r\n")));

    // return the Host Controller context
    return (DWORD)pHostContext;
}

void SDControllerPowerDown( PSDH_HARDWARE_CONTEXT pController );
void SDControllerPowerUp( PSDH_HARDWARE_CONTEXT pController );

///////////////////////////////////////////////////////////////////////////////
//  SDH_IOControl - the I/O control entry point
//  Input:  hOpenContext - the context returned from SDH_Open
//          dwCode - the ioctl code
//          pBufIn - the input buffer from the user
//          dwLenIn - the length of the input buffer
//          pBufOut - the output buffer from the user
//          dwLenOut - the length of the output buffer
//          pdwActualOut - the size of the transfer
//  Output:
//  Return: FALSE
//  Notes:  Not used
///////////////////////////////////////////////////////////////////////////////
BOOL SDH_IOControl(DWORD   hOpenContext,
    DWORD   dwCode,
    PBYTE   pBufIn,
    DWORD   dwLenIn,
    PBYTE   pBufOut,
    DWORD   dwLenOut,
    PDWORD  pdwActualOut)
{
    PSDCARD_HC_CONTEXT pHostContext;
    PSDH_HARDWARE_CONTEXT pController = NULL;
    BOOL retValue = FALSE;

    DbgPrintZo(SDCARD_ZONE_FUNC, (TEXT("SDH: +-SDH_IOControl \r\n")));

    pHostContext = (PSDCARD_HC_CONTEXT)hOpenContext;
    if (pHostContext != NULL)
        pController = (PSDH_HARDWARE_CONTEXT) pHostContext->pHCSpecificContext;
    if (pController == NULL)
        return(FALSE);

    switch (dwCode) {

    case IOCTL_POWER_CAPABILITIES:

        if (pBufOut != NULL && pdwActualOut != NULL && dwLenOut >= sizeof(POWER_CAPABILITIES))
        {
        __try
        {
                POWER_CAPABILITIES* power_caps = (POWER_CAPABILITIES*)pBufOut;
                memset(power_caps, 0, sizeof(POWER_CAPABILITIES));
                // support D0, D3, D4
                power_caps->DeviceDx = DX_MASK(D0)|DX_MASK(D2)|DX_MASK(D3)|DX_MASK(D4);
                *pdwActualOut = sizeof(POWER_CAPABILITIES);
                retValue = TRUE;
        }
            __except(EXCEPTION_EXECUTE_HANDLER)
            {
                DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("exception in ioctl\r\n")));
            }
    }
        break;

    case IOCTL_POWER_SET:

        if(pBufOut != NULL && pdwActualOut != NULL && dwLenOut >= sizeof(CEDEVICE_POWER_STATE))
        {
        __try
        {
                CEDEVICE_POWER_STATE* state = (CEDEVICE_POWER_STATE*)pBufOut;

                if (*state == D3 || *state == D4) {
                    RETAILMSG(1,  (TEXT("[%s] SDH_IOControl: Entering D3/D4...\r\n"), pController->szName));
                    SDControllerPowerDown(pController);
/*                } else if (*state == D2) {
                    RETAILMSG(1, (TEXT("[MMC] SDH-IOControl: Entering D2...\n")));
                    SDControllerPowerDown(pController);*/
                 } else if (*state == D0) {
                    RETAILMSG(1,  (TEXT("[%s] SDH_IOControl: Entering D0...\r\n"),pController->szName));
                    SDControllerPowerUp(pController);
                } else
                    *state = pController->gPowerState; // power state doesn't change

                *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
                pController->gPowerState = *state;
                retValue = TRUE;
            }
            __except(EXCEPTION_EXECUTE_HANDLER)
            {
                DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("exception in ioctl\r\n")));
            }
    }

        break;

    case IOCTL_POWER_GET:

        if(pBufOut != NULL && pdwActualOut != NULL && dwLenOut >= sizeof(CEDEVICE_POWER_STATE))
        {
        __try
        {
                *(PCEDEVICE_POWER_STATE) pBufOut = pController->gPowerState;
                *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
                retValue = TRUE;
            }
            __except(EXCEPTION_EXECUTE_HANDLER)
            {
                DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("exception in ioctl\r\n")));
            }
    }
        break;
    default:
        retValue = FALSE;
        break;
    }
    return (retValue);
}

///////////////////////////////////////////////////////////////////////////////
//  SDH_Open - the open entry point for the bus driver
//  Input:  hDeviceContext - the device context from SDH_Init
//          AccessCode - the desired access
//          ShareMode - the desired share mode
//  Output:
//  Return: hDeviceContext
//  Notes:  not used
///////////////////////////////////////////////////////////////////////////////
DWORD SDH_Open(DWORD    hDeviceContext,
               DWORD    AccessCode,
               DWORD    ShareMode)
{
    DbgPrintZo(SDCARD_ZONE_FUNC, (TEXT("SDH: +-SDH_Open\n")));
    return hDeviceContext;
}



///////////////////////////////////////////////////////////////////////////////
//  SDH_Close - the close entry point
//  Input:  hOpenContext - the context returned from SDH_Open
//  Output:
//  Return: TRUE
//  Notes:  not used
///////////////////////////////////////////////////////////////////////////////
BOOL SDH_Close(DWORD hOpenContext)
{
    DbgPrintZo(SDCARD_ZONE_FUNC, (TEXT("SDH: +-SDH_Close\n")));
    return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
//  SDH_PowerDown - the power down entry point
//  Input:  hDeviceContext - the device context from SDH_Init
//  Output:
//  Notes:  preforms no actions
///////////////////////////////////////////////////////////////////////////////
void SDH_PowerDown(DWORD    hDeviceContext)
{

    PSDCARD_HC_CONTEXT pHostContext;

    DbgPrintZo(SDCARD_ZONE_INIT, (TEXT("SDH: +SDH_PowerDown\r\n")));
    RETAILMSG(1,  (TEXT("[MMC] SDH: +SDH_PowerDown\r\n")));

    pHostContext = (PSDCARD_HC_CONTEXT) hDeviceContext;
    if (pHostContext != NULL) {
        SDHCDPowerUpDown(pHostContext, FALSE, FALSE, 0);
        //SDControllerPowerDown(pController);
    }

    return;
}

///////////////////////////////////////////////////////////////////////////////
//  SDH_PowerUp - the power up entry point
//  Input:  hDeviceContext - the device context from SDH_Init
//  Output:
//  Notes:  preforms no actions
///////////////////////////////////////////////////////////////////////////////
void SDH_PowerUp(DWORD  hDeviceContext)
{
    PSDCARD_HC_CONTEXT pHostContext;

    DbgPrintZo(SDCARD_ZONE_INIT, (TEXT("SDH: +SDH_PowerUp\r\n")));

    pHostContext = (PSDCARD_HC_CONTEXT) hDeviceContext;
    if (pHostContext != NULL) {
        SDHCDPowerUpDown(pHostContext, TRUE, FALSE, 0);
    }
    RETAILMSG(1, (TEXT("[MMC] SDH: -SDH_PoweUp\r\n")));

    return;
}

///////////////////////////////////////////////////////////////////////////////
//  SDH_Read - the read entry point for the CE file system wrapper
//  Input:  hOpenContext - the context from SDH_Open
//          pBuffer - the user's buffer
//          Count - the size of the transfer
//  Output:
//  Return: zero
//  Notes:  not used
///////////////////////////////////////////////////////////////////////////////
DWORD SDH_Read(DWORD    hOpenContext,
               LPVOID   pBuffer,
               DWORD    Count)
{
    DbgPrintZo(SDCARD_ZONE_FUNC, (TEXT("SDH: +-SDH_Read\n")));
    return 0;
}

///////////////////////////////////////////////////////////////////////////////
//  SDH_Seek - the seek entry point for the CE file system wrapper
//  Input:  hOpenContext - the context from SDH_Open
//          Amount - the amount to seek
//          Type - the type of seek
//  Output:
//  Return: zero
//  Notes:  not used
///////////////////////////////////////////////////////////////////////////////
DWORD SDH_Seek(DWORD    hOpenContext,
               long     Amount,
               DWORD    Type)
{
    DbgPrintZo(SDCARD_ZONE_FUNC, (TEXT("SDH: +-SDH_Seek\n")));
    return 0;
}

///////////////////////////////////////////////////////////////////////////////
//  SDH_Write - the write entry point for the CE file system wrapper
//  Input:  hOpenContext - the context from SDH_Open
//          pBuffer - the user's buffer
//          Count - the size of the transfer
//  Output:
//  Return: zero
//  Notes:  Not used
///////////////////////////////////////////////////////////////////////////////
DWORD SDH_Write(DWORD   hOpenContext,
                LPCVOID pBuffer,
                DWORD   Count)
{
    DbgPrintZo(SDCARD_ZONE_FUNC, (TEXT("SDH: +-SDH_Write\n")));
    return 0;
}

#define CONTROLLER_IRQ_TEXT _T("ControllerIRQ")
#define CONTROLLER_IST_PRI_TEXT _T("ControllerISTPriority")
#define CLOCK_ALWAYS_ON_TEXT _T("ClockAlwaysOn")
#define CLOCK_ON_IF_INTERRUPTS_ENABLED_TEXT _T("ClockOnIfInterruptsEnabled")
#define SDHC_INDEX _T("SDHCIndex")
#define CARDDETECT_IST_PRI_TEXT _T("CardDetectISTPriority")
#define HOT_PLUGIN_N_REMOVABLE _T("HotPluginNRemovable")
#define DEFAULT_CARD_DETECT_IST_PRIORITY 101

#define CONTROLLER_POLLING_MODE_TEXT _T("PollingModeSize")
#define MAXIMUM_CLOCK_FREQUENCY_TEXT _T("MaximumClockFrequency")
#define FAST_PATH_ENABLE_TEXT _T("FastPathEnabled")

BOOL LoadRegistrySettings( HKEY hKeyDevice, PSDH_HARDWARE_CONTEXT pController )
{
    DWORD dwRegVal;
    DWORD dwDataSize;
    DWORD dwType;

    /*dwDataSize = sizeof(pController->szName);
    if (ERROR_SUCCESS != RegQueryValueEx(hKeyDevice, L"Name", NULL,
                               &dwType, (LPBYTE)pController->szName, &dwDataSize) )
    {
        return FALSE;
    } */

    dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, SDHC_INDEX,
                                          NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
        REG_DWORD == dwType )
    {
        pController->dwSDHCIndex = dwRegVal;
    }
    else
    {
        return FALSE;
    }

    dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, CONTROLLER_IRQ_TEXT,
                                          NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
        REG_DWORD == dwType )
    {
        pController->dwSDMMCIrq = dwRegVal;
    }
    else
    {
        return FALSE;
    }

    dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, CLOCK_ALWAYS_ON_TEXT,
                                          NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
        REG_DWORD == dwType )
    {
        pController->fClockAlwaysOn = dwRegVal ? TRUE : FALSE;
    }
    else
    {
        pController->fClockAlwaysOn = FALSE;
    }

    dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, CLOCK_ON_IF_INTERRUPTS_ENABLED_TEXT,
                                          NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
        REG_DWORD == dwType )
    {
        pController->fClockOnIfInterruptsEnabled = dwRegVal ? TRUE : FALSE;
    }
    else
    {
        pController->fClockOnIfInterruptsEnabled = FALSE;
    }

    dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, CONTROLLER_IST_PRI_TEXT,
                                          NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
        REG_DWORD == dwType )
    {
        pController->ControllerIstThreadPriority = dwRegVal;
    }
    else
    {
        pController->ControllerIstThreadPriority = SDH_CARD_CONTROLLER_PRIORITY;
    }

    //PNP
    dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, HOT_PLUGIN_N_REMOVABLE,
            NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
            REG_DWORD == dwType ){
        pController->hotRemovable= (0==dwRegVal)?FALSE:TRUE;
    }else{
        pController->hotRemovable= TRUE;
    }

    //card detect ist priority
    dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, CARDDETECT_IST_PRI_TEXT,
            NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
            REG_DWORD == dwType ){
        pController->dwCardDetectIstThreadPriority = dwRegVal;
    }else{
        pController->dwCardDetectIstThreadPriority = DEFAULT_CARD_DETECT_IST_PRIORITY;
    }

    RETAILMSG(1, (TEXT("[%s]: registry loaded\r\n"), pController->szName));

dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, CONTROLLER_POLLING_MODE_TEXT,
                                          NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
        REG_DWORD == dwType )
    {
        pController->dwPollingModeSize = dwRegVal;
    }
    else
    {
        pController->dwPollingModeSize = NUM_BYTE_FOR_POLLING_MODE;
    }


    dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, MAXIMUM_CLOCK_FREQUENCY_TEXT,
                                          NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
        REG_DWORD == dwType )
    {
        pController->dwMaximumSDClockFrequency = dwRegVal;
    }
    else
    {
        pController->dwMaximumSDClockFrequency = MAXIMUM_SDCLOCK_FREQUENCY;
    }


    dwDataSize = sizeof(DWORD);
    if( ERROR_SUCCESS == RegQueryValueEx( hKeyDevice, FAST_PATH_ENABLE_TEXT,
                                          NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize ) &&
        REG_DWORD == dwType )
    {
        pController->fFastPathEnabled = dwRegVal ? TRUE : FALSE;
    }
    else
    {
        pController->fFastPathEnabled = FALSE;
    }
    return TRUE; //LoadPlatformRegistrySettings(hKeyDevice);
}



// DO NOT REMOVE --- END EXTERNALLY DEVELOPED SOURCE CODE ID --- DO NOT REMOVE

